package cn.hackcloud.demo.dubbo.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.apache.dubbo.common.utils.NamedThreadFactory;
import org.apache.dubbo.rpc.AsyncContext;
import org.apache.dubbo.rpc.RpcContext;
import org.springframework.stereotype.Service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;

import cn.hackcloud.demo.dubbo.bean.UserAddress;
import cn.hackcloud.demo.dubbo.rpc.IUserService;

/**
 * @author FM
 */
@Service(value = "userService")
public class UserServiceImpl implements IUserService {
    private final ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(8, 16, 1, TimeUnit.MINUTES, new SynchronousQueue<>(),
            new NamedThreadFactory("biz"), new ThreadPoolExecutor.CallerRunsPolicy());
    static List<UserAddress> list = new ArrayList<>();

    static {
        UserAddress address1 = new UserAddress(1, "重庆", "1", "李老师", "010-56253825", "Y");
        UserAddress address2 = new UserAddress(2, "成都", "2", "王老师", "010-56253825", "N");

        list.add(address1);
        list.add(address2);
    }

    /**
     * 基于CompletableFuture的签名的接口实现异步执行
     *
     * @param userId
     * @return
     */
    @Override
    public CompletableFuture<List<UserAddress>> async2(String userId) {
        return CompletableFuture.supplyAsync(() -> list.stream().filter(x -> x.getUserId().equals(userId)).collect(Collectors.toList()), poolExecutor);
    }


    @HystrixCommand(commandProperties = {
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000")})
    @Override
    public List<UserAddress> sync(String userId) {
        System.out.println(RpcContext.getContext().getAttachment("bizNo"));
        return list;
    }

    /**
     * asyncContext实现异步执行
     *
     * @param userId
     * @return
     */

    @Override
    public List<UserAddress> async(String userId) {
        final AsyncContext asyncContext = RpcContext.startAsync();
        poolExecutor.execute(() -> {
            asyncContext.signalContextSwitch();
            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
            }
            asyncContext.write(list.stream().filter(x -> x.getUserId().equals(userId)).collect(Collectors.toList()));
        });
        return new ArrayList<>();
        // throw new RuntimeException("Exception to show hystrix enabled.");
    }

    @Override
    @SentinelResource(value = "sentinel", blockHandler = "exceptionHandler", fallback = "helloFallback")
    public String sentinel(String json) throws InterruptedException {
        TimeUnit.SECONDS.sleep(1);
        return json;
    }

}
